/**************************************************************************
** Qt Creator license header template
**   Special keywords: Programmer 2012/5/11 2012
**   Environment variables: 
**   To protect a percent sign, use '%'.
**************************************************************************/

#ifndef PROGRESSIVEMESH_H
#define PROGRESSIVEMESH_H
//std
#include <stack>

//vcg
#include <vcg/complex/algorithms/local_optimization.h>
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
#include <vcg/container/simple_temporary_data.h>

//meshlab
#include <common/meshmodel.h>


#include "myedgecollasper.h"

typedef vcg::SimpleTempData<CMeshO::VertContainer,vcg::math::Quadric<double> > QuadricTemp;
typedef vcg::tri::BasicVertexPair<CVertexO> VertexPair;

class VSplit
{
public:
    VSplit(CVertexO* _v,CVertexO* _vl,CVertexO* _vr, CMeshO::CoordType _v0,CMeshO::CoordType _v1){

        v = _v; vl = _vl; vr = _vr; v0 = _v0; v1 = _v1;
    }

    CVertexO* v;
    CVertexO* vl;
    CVertexO* vr;
    CMeshO::CoordType v0;
    CMeshO::CoordType v1;
};
struct Record{
    unsigned int v;
    unsigned int vl;
    unsigned int vr;

    CMeshO::CoordType v0;
    CMeshO::CoordType v1;

    Record(){
        v = vl = vr = 0;
    }

};
class ProgressiveMeshParameter : public vcg::tri::TriEdgeCollapseQuadricParameter
{
public:
    ProgressiveMeshParameter():vcg::tri::TriEdgeCollapseQuadricParameter(){}

    //add items
    void addSplit(VSplit* vs){ vSplits.push(vs); }
    void addDeletedFace(CMeshO::FacePointer f){ deletedFaces.push(f); }
    void addDeletedVertex(CMeshO::VertexPointer v){ deletedVertices.push(v); }

    //get and remove
    VSplit* getRemoveSplit(){
        VSplit* s = vSplits.top();
        vSplits.pop();
        return s;
    }

    CMeshO::FacePointer getRemoveFace(){
        CMeshO::FacePointer f = deletedFaces.top();
        deletedFaces.pop();
        return f;
    }

    CMeshO::VertexPointer getRemoveVertex(){
        CMeshO::VertexPointer v = deletedVertices.top();
        deletedVertices.pop();
        return v;
    }


    std::stack<VSplit*> vSplits;
    std::stack<CMeshO::FacePointer> deletedFaces;
    std::stack<CMeshO::VertexPointer> deletedVertices;
};

class Helper{
public:
    Helper(){}

    static void Init(){}
    static vcg::math::Quadric<double> &Qd(CVertexO &v){return TD()[v];}
    static vcg::math::Quadric<double> &Qd(CVertexO *v){return TD()[v];}
    static CMeshO::ScalarType W(CVertexO*){return 1.0;}
    static CMeshO::ScalarType W(CVertexO&){return 1.0;}
    static void Merge(CVertexO&,CVertexO const &){}
    static QuadricTemp* &TDp(){static QuadricTemp* td; return td;}
    static QuadricTemp &TD(){return *TDp();}
};

class MeshSimplification : public vcg::tri::TriEdgeCollapseQuadric<CMeshO,VertexPair,MeshSimplification,Helper>
{
public:
    typedef vcg::tri::TriEdgeCollapseQuadric<CMeshO,VertexPair,MeshSimplification,Helper> TECQ;
    typedef ProgressiveMeshParameter PMParameter;
    inline MeshSimplification(const VertexPair& p, int i,vcg::BaseParameterClass* pp) : TECQ(p,i,pp){}

    virtual void Execute(CMeshO &m, vcg::BaseParameterClass *_pp){
        PMParameter* pp = (PMParameter*)_pp;
        CoordType newPos;
        if(pp->OptimalPlacement) newPos = static_cast<MeshSimplification*>(this)->ComputeMinimal();
        else newPos = this->pos.V(1)->P();

        Helper::Qd(this->pos.V(1)) += Helper::Qd(this->pos.V(0));
        MyEdgeCollasper<CMeshO,VertexPair,PMParameter,VSplit>::Do(m,this->pos,newPos,*pp);

    }
};

void simplify(CMeshO& m,int TargetFaceNum, bool Selected, ProgressiveMeshParameter& pp, vcg::CallBackPos* cb);

void FindEdgeSet(std::vector<vcg::face::VFIterator<CFaceO> >& es,VSplit* s);
//create file XX.prm at the same location with model file.
void saveRecordsToFile(std::vector<Record>& records,std::string filePathName, vcg::CallBackPos cb);
void restore(CMeshO& m,ProgressiveMeshParameter& pp,vcg::CallBackPos* cb, std::string fullPathName);

class ProgressiveMesh
{
public:
    ProgressiveMesh();
};

#endif // PROGRESSIVEMESH_H
